﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Reflection;
using UmlControlLibrary.Tools;

namespace UmlControlLibrary
{
    public class UmlParameter : UmlElement, INotifyPropertyChanged
    {
        private string _typeName = "";
        public string TypeName
        {
            get { return _typeName; }
            set
            {
                _typeName = value;
                OnPropertyChanged("TypeName");
            }
        }

        private string _parameterName = "";
        public string ParameterName
        {
            get { return _parameterName; }
            set
            {
                _parameterName = value;
                OnPropertyChanged("ParameterName");
            }

        }

        public string ElementLabel
        {
            get
            {
                return TypeName + " " + ParameterName;
            }
            set
            {

            }
        }

        public UmlParameter(string name, string type)
        {
            ParameterName = name;
            TypeName = type;
        }
    }

    public class UmlMethod : UmlMemberElement
    {
        public new class Events
        {
            public static Event Created = new Event(Event.Created, typeof(UmlMethod));
            public static Event Modified = new Event(Event.Modified, typeof(UmlMethod));
            public static Event Deleted = new Event(Event.Deleted, typeof(UmlMethod));
        }

        public UmlElement Owner
        {
            get;
            set;
        }

        public override string ElementLabel
        {
            get
            {
                string l = "";
                if (StereoType.Length > 0)
                    l = "« " + StereoType + " » ";

                if ((Modifiers & UmlModifier._public) != 0)
                    l += "+";
                if ((Modifiers & UmlModifier._private) != 0)
                    l += "-";
                if ((Modifiers & UmlModifier._protected) != 0)
                    l += "#";

                l += TypeName;
                l += " " + ElementName + "(";

                for (int i = 0; i < Parameters.Count; i++)
                {
                    if (i > 0) l += ", ";
                    l += Parameters[i].ElementLabel;
                }

                l += ")";
                return l;
            }
            set
            {
                /*  UmlModifier m;
                  value = value.Trim();
                  if (value.Length > 1)
                  {
                      string s = value.Substring(0, 1);
                      if (s == "-") m = UmlModifier._private;
                      else if (s == "#") m = UmlModifier._protected;
                      else if (s == "+") m = UmlModifier._public;
                      else
                      {
                          m = UmlModifier._public;
                          value = s + value;
                      }
                      value = value.Substring(1).Trim();

                      if (value.Length > 0)
                      {
                          int i = value.IndexOf(':');
                          string type = null;
                          if (i >= 0)
                          {
                              type = value.Substring(i + 1).Trim();
                              value = value.Substring(0, i).Trim();
                          }
                          if (value.Length > 0)
                          {
                              Modifier = m;
                              ReturnTypeName = type ?? "string";
                              if (value.StartsWith("/"))
                                  value = value.Substring(1);
                              MethodName = value;
                          }
                      }
                  }
                  OnPropertyChanged("MethodLabel");*/
            }

        }


        private string _returnTypeName;
        public override string TypeName
        {
            get { return _returnTypeName; }
            set
            {
                value = value.Trim();
                UmlElement e = UmlModel.CurrentDiagram.GetElementByName(value);
                if (e != null)
                    value = e.Name;
                if (value.Length > 0) _returnTypeName = value;
                OnPropertyChanged("TypeName");
                OnPropertyChanged("ElementLabel");
                EventService.BroadcastEvent(this, UmlMethod.Events.Modified);
            }
        }

        private string _body = "";
        public string Body
        {
            get { return _body; }
            set
            {
                _body = value;
                OnPropertyChanged("Body");
            }
        }

        private ObservableCollection<UmlParameter> _parameters = new ObservableCollection<UmlParameter>();
        public ObservableCollection<UmlParameter> Parameters
        {
            get { return _parameters; }
            set
            {
                _parameters = value;
                OnPropertyChanged("Parameters");
            }
        }

        void _parameters_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            OnPropertyChanged("Parameters");
        }

        public void AddParameter(string name, string type)
        {
            Parameters.Add(new UmlParameter(name, type));
        }

        public UmlMethod(string name, string type, UmlModifier modifier, UmlParameter[] parameters)
            : this(name, type, modifier)
        {
            foreach (UmlParameter p in parameters)
                Parameters.Add(p);
        }

        public UmlMethod(string name, string type, UmlModifier modifier)
        {
            EventService.StopBroadcasting(this);
            this.ElementName = name;
            this.Modifiers = modifier;
            this.TypeName = type;
            EventService.ResumeBroadcasting(this);
            _parameters.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_parameters_CollectionChanged);
        }

        public UmlMethod(string name, UmlModifier modifier)
            : this(name, "void", modifier)
        {
        }
        public UmlMethod(string name)
            : this(name, UmlModifier._public)
        {
        }
        private UmlMethod()
        {
        }

        public UmlMethod(MethodInfo method)
            : this(method.Name,
                (method.ReturnType != null ? AssemblyLoader.GetTypeName(method.ReturnType) : "void"),
                UmlModifierItem.GetUmlModifiers(method.Attributes))
        {
            ParameterInfo[] parameters = method.GetParameters();

            foreach (ParameterInfo pInfo in parameters)
            {
                UmlParameter p = new UmlParameter(pInfo.Name, AssemblyLoader.GetTypeName(pInfo.ParameterType));
                Parameters.Add(p);
            }

//            this.MethodList.Add(new UmlMethod(method.Name, returnType, UmlModifier._public));
        }

        public void CopyFrom(UmlMethod from)
        {
            // should be a call to some reflection based properties copy method...

            ElementName = from.ElementName;
            Modifiers = from.Modifiers;
            TypeName = from.TypeName;
            StereoType = from.StereoType;
            Body = from.Body;
        }

        #region ICloneable Members

        public object Clone()
        {
            return this.MemberwiseClone();
        }

        public override ObservableCollection<UmlElement> GetChilds()
        {
            ObservableCollection<UmlElement> elements = new ObservableCollection<UmlElement>();
            UmlElement element = null;//UmlElementList.Instance.GetElementByName(this.TypeName);
            if (element != null)
                elements.Add(element);
            return elements;
        }

        #endregion
    }
}
